﻿//===============================================================================  
// 产品名称：网鸟网站内容管理系统(Htmlbird CMS)  
// 产品作者：YMind Chan  
// 版权所有：彦铭工作室 网鸟IT技术论坛  
//===============================================================================  
// Copyright © Htmlbird.Net. All rights reserved.  
// 官方网站：http://www.htmlbird.net/  
// 技术论坛：http://bbs.htmlbird.net/  
//===============================================================================  

using System;
using System.Collections;
using System.Web;
using System.Web.Caching;

namespace GaiNo.Core.Helpers
{
    /// <summary>  
    /// 实现用于 Web 应用程序的缓存管理。无法继承此类。  
    /// </summary>  
    public sealed class CacheHelper
    {
        private static readonly object _lock = new object();
        private static CacheHelper _obj = null;
        public static CacheHelper CreateInstance()
        {
            if (_obj == null)
            {
                lock (_lock)
                {
                    if (_obj == null)
                    {
                        _obj = new CacheHelper();
                    }
                }
            }
            return _obj;
        }
        #region 私有字段

        private const string _DefaultPrefix = "Ast_Web_Default";
        private string _Prefix;

        #endregion

        #region 构造函数

        /// <summary>  
        /// 初始化缓存管理器对象。  
        /// </summary>  
        public CacheHelper()
        {
            _Prefix = _DefaultPrefix;
        }

        #endregion

        #region 私有方法

        /// <summary>  
        /// 检查给定的缓存键是否合法，如果不合法则直接修正它。  
        /// </summary>  
        /// <param name="key">要检查的缓存键。</param>  
        /// <returns>经过检查并修正的缓存键。</returns>  
        private string _CheckCacheKey(string key)
        {
            if (key.StartsWith(_Prefix + "-") == false)
                key = String.Format("{0}-{1}", _Prefix, key);

            return key;
        }

        #endregion

        #region 公有方法

        #region 添加缓存

        /// <summary>  
        /// 添加一个缓存对象。  
        /// </summary>  
        /// <param name="key">用于引用该项的缓存键。</param>  
        /// <param name="value">要插入缓存中的对象。</param>  
        public void Add(string key, object value)
        {
            this.Add(key, value, new TimeSpan(0, 10, 0));
        }

        /// <summary>  
        /// 添加一个缓存对象。  
        /// </summary>  
        /// <param name="key">用于引用该项的缓存键。</param>  
        /// <param name="value">要插入缓存中的对象。</param>  
        /// <param name="absoluteExpiration">所插入对象将过期并被从缓存中移除的时间。</param>  
        public void Add(string key, object value, TimeSpan absoluteExpiration)
        {
            this.Add(key, value, DateTime.Now.Add(absoluteExpiration), TimeSpan.Zero);
        }

        /// <summary>  
        /// 添加一个缓存对象。  
        /// </summary>  
        /// <param name="key">用于引用该项的缓存键。</param>  
        /// <param name="value">要插入缓存中的对象。</param>  
        /// <param name="dependencies">所插入对象的文件依赖项或缓存键依赖项。当任何依赖项更改时，该对象即无效，并从缓存中移除。如果没有依赖项，则此参数包含 null。</param>  
        /// <param name="absoluteExpiration">所插入对象将过期并被从缓存中移除的时间。</param>  
        public void Add(string key, object value, CacheDependency dependencies, TimeSpan absoluteExpiration)
        {
            this.Add(key, value, dependencies, DateTime.Now.Add(absoluteExpiration), TimeSpan.Zero);
        }

        /// <summary>  
        /// 添加一个缓存对象。  
        /// </summary>  
        /// <param name="key">用于引用该项的缓存键。</param>  
        /// <param name="value">要插入缓存中的对象。</param>  
        /// <param name="absoluteExpiration">所插入对象将过期并被从缓存中移除的时间。如果使用绝对过期，则 slidingExpiration 参数必须为 System.Web.Caching.Cache.NoSlidingExpiration。</param>  
        /// <param name="slidingExpiration">最后一次访问所插入对象时与该对象过期时之间的时间间隔。如果该值等效于  分钟，则对象在最后一次被访问  分钟之后将过期并被从缓存中移除。如果使用可调过期，则absoluteExpiration 参数必须为 System.Web.Caching.Cache.NoAbsoluteExpiration。</param>  
        public void Add(string key, object value, DateTime absoluteExpiration, TimeSpan slidingExpiration)
        {
            this.Add(key, value, null, absoluteExpiration, slidingExpiration);
        }

        /// <summary>  
        /// 添加一个缓存对象。  
        /// </summary>  
        /// <param name="key">用于引用该项的缓存键。</param>  
        /// <param name="value">要插入缓存中的对象。</param>  
        /// <param name="dependencies">所插入对象的文件依赖项或缓存键依赖项。当任何依赖项更改时，该对象即无效，并从缓存中移除。如果没有依赖项，则此参数包含 null。</param>  
        /// <param name="absoluteExpiration">所插入对象将过期并被从缓存中移除的时间。如果使用绝对过期，则 slidingExpiration 参数必须为 System.Web.Caching.Cache.NoSlidingExpiration。</param>  
        /// <param name="slidingExpiration">最后一次访问所插入对象时与该对象过期时之间的时间间隔。如果该值等效于  分钟，则对象在最后一次被访问  分钟之后将过期并被从缓存中移除。如果使用可调过期，则absoluteExpiration 参数必须为 System.Web.Caching.Cache.NoAbsoluteExpiration。</param>  
        public void Add(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration)
        {
            this.Add(key, value, dependencies, absoluteExpiration, slidingExpiration, CacheItemPriority.Default, null);
        }

        /// <summary>  
        /// 添加一个缓存对象。  
        /// </summary>  
        /// <param name="key">用于引用该项的缓存键。</param>  
        /// <param name="value">要插入缓存中的对象。</param>  
        /// <param name="absoluteExpiration">所插入对象将过期并被从缓存中移除的时间。如果使用绝对过期，则 slidingExpiration 参数必须为 System.Web.Caching.Cache.NoSlidingExpiration。</param>  
        /// <param name="slidingExpiration"> 最后一次访问所插入对象时与该对象过期时之间的时间间隔。如果该值等效于  分钟，则对象在最后一次被访问  分钟之后将过期并被从缓存中移除。如果使用可调过期，则absoluteExpiration 参数必须为 System.Web.Caching.Cache.NoAbsoluteExpiration。</param>  
        /// <param name="priority">该对象相对于缓存中存储的其他项的成本，由 System.Web.Caching.CacheItemPriority 枚举表示。该值由缓存在退出对象时使用；具有较低成本的对象在具有较高成本的对象之前被从缓存移除。</param>  
        /// <param name="onRemoveCallback">在从缓存中移除对象时将调用的委托（如果提供）。当从缓存中删除应用程序的对象时，可使用它来通知应用程序。</param>  
        public void Add(string key, object value, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback)
        {
            this.Add(key, value, null, absoluteExpiration, slidingExpiration, priority, onRemoveCallback);
        }

        /// <summary>  
        /// 添加一个缓存对象。  
        /// </summary>  
        /// <param name="key">用于引用该项的缓存键。</param>  
        /// <param name="value">要插入缓存中的对象。</param>  
        /// <param name="dependencies">所插入对象的文件依赖项或缓存键依赖项。当任何依赖项更改时，该对象即无效，并从缓存中移除。如果没有依赖项，则此参数包含 null。</param>  
        /// <param name="absoluteExpiration">所插入对象将过期并被从缓存中移除的时间。如果使用绝对过期，则 slidingExpiration 参数必须为 System.Web.Caching.Cache.NoSlidingExpiration。</param>  
        /// <param name="slidingExpiration"> 最后一次访问所插入对象时与该对象过期时之间的时间间隔。如果该值等效于  分钟，则对象在最后一次被访问  分钟之后将过期并被从缓存中移除。如果使用可调过期，则absoluteExpiration 参数必须为 System.Web.Caching.Cache.NoAbsoluteExpiration。</param>  
        /// <param name="priority">该对象相对于缓存中存储的其他项的成本，由 System.Web.Caching.CacheItemPriority 枚举表示。该值由缓存在退出对象时使用；具有较低成本的对象在具有较高成本的对象之前被从缓存移除。</param>  
        /// <param name="onRemoveCallback">在从缓存中移除对象时将调用的委托（如果提供）。当从缓存中删除应用程序的对象时，可使用它来通知应用程序。</param>  
        public void Add(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback)
        {
            if (value == null)
                return;
            HttpContext.Current.Cache.Insert(_CheckCacheKey(key), value, dependencies, absoluteExpiration, slidingExpiration, priority, onRemoveCallback);
        }

        #endregion

        #region 删除缓存

        /// <summary>  
        /// 从 Cache 移除指定项。  
        /// </summary>  
        /// <param name="key">要移除的缓存项的 System.String 标识符。</param>  
        /// <returns>从 CacheStrategy.Cache 移除的项。如果未找到键参数中的值，则返回null。</returns>  
        public object Remove(string key)
        {
            return HttpContext.Current.Cache.Remove(_CheckCacheKey(key));
        }

        #endregion

        #region 获取缓存数目

        /// <summary>  
        /// 根据键名前缀返回缓存项数。注意该方法返回的是仅仅以 prefix 为前缀的缓存项目的总数。  
        /// </summary>  
        /// <param name="prefix">指定的缓存键名前缀。</param>  
        /// <returns>以 prefix 为前缀的缓存项目的总数。</returns>  
        public int GetCountByPrefix(string prefix)
        {
            int i = 0;

            IDictionaryEnumerator E = HttpContext.Current.Cache.GetEnumerator();

            while (E.MoveNext())
            {
                if (E.Key.ToString().StartsWith(prefix) == true)
                    i++;
            }

            return i;
        }

        #endregion

        #region 判断缓存是否已经存在

        /// <summary>  
        /// 判断给定的键是否已经拥有缓存项。  
        /// </summary>  
        /// <param name="key">用于引用该项的缓存键。</param>  
        /// <returns>返回 true 表示已经存在缓存项。</returns>  
        public bool Contains(string key)
        {
            return this.Get(key) != null;
        }

        #endregion

        #region 读取缓存

        /// <summary>  
        /// 从 Cache 对象检索指定项。  
        /// </summary>  
        /// <param name="key">要检索的缓存项的标识符。</param>  
        /// <returns>检索到的缓存项，未找到该键时为null。</returns>  
        public object Get(string key)
        {
            return HttpContext.Current.Cache.Get(_CheckCacheKey(key));
        }

        #endregion

        #region 删除所有缓存

        /// <summary>  
        /// 重置缓存管理器，这将清空所有已缓存的项。  
        /// </summary>  
        public void Reset()
        {
            IDictionaryEnumerator E = HttpContext.Current.Cache.GetEnumerator();

            while (E.MoveNext())
            {
                HttpContext.Current.Cache.Remove(_CheckCacheKey((string)E.Key));
            }
        }

        #endregion

        #endregion

        #region 公有属性

        /// <summary>  
        /// 获取当前缓存项数。  
        /// </summary>  
        public int Count { get { return HttpContext.Current.Cache.Count; } }

        /// <summary>  
        /// 设置或获取缓存键名前缀。  
        /// </summary>  
        public string Prefix
        {
            get
            {
                if (String.IsNullOrEmpty(_Prefix))
                    _Prefix = _DefaultPrefix;

                return _Prefix;
            }
            set { _Prefix = value; }
        }

        /// <summary>  
        /// 设置或获取指定键处的缓存项。  
        /// </summary>  
        /// <param name="key">表示缓存项的键的 System.String 对象。</param>  
        /// <returns>指定的缓存项。</returns>  
        public object this[string key]
        {
            get { return HttpContext.Current.Cache.Get(_CheckCacheKey(key)); }
            set { HttpContext.Current.Cache.Insert(_CheckCacheKey(key), value); }
        }

        /// <summary>  
        /// 获取在 ASP.NET 开始从缓存中移除项之前应用程序可使用的物理内存百分比。  
        /// </summary>  
        public long EffectivePercentagePhysicalMemoryLimit { get { return HttpContext.Current.Cache.EffectivePercentagePhysicalMemoryLimit; } }

        /// <summary>  
        /// 获取可用于缓存的字节数。  
        /// </summary>  
        public long EffectivePrivateBytesLimit { get { return HttpContext.Current.Cache.EffectivePrivateBytesLimit; } }

        #endregion
    }
}
